package com.jzhao.jpre.channel.comm;

import java.nio.channels.SelectionKey;

/**
 * A type-safe mask that is used to control the mode of {@link CommLink}
 * with {@link CommLink#setModeMask(CommModeMask)}.
 *
 */
public class CommModeMask {
    /**
     * This mask suspends both reads and writes.
     */
    public static final CommModeMask NONE = new CommModeMask(0, "none");

    /**
     * This mask suspends writes, and resumes reads if reads were suspended.
     */
    public static final CommModeMask READ = new CommModeMask(
            SelectionKey.OP_READ, "read");

    /**
     * This mask suspends reads, and resumes writes if writes were suspended.
     */
    public static final CommModeMask WRITE = new CommModeMask(
            SelectionKey.OP_WRITE, "write");

    /**
     * This mask resumes both reads and writes if any of them were suspended.
     */
    public static final CommModeMask ALL = new CommModeMask(SelectionKey.OP_READ
            | SelectionKey.OP_WRITE, "all");

    /**
     * Returns an appropriate {@link CommModeMask} instance from the
     * specified <tt>interestOps</tt>.
     * @see SelectionKey
     */
    public static CommModeMask getInstance(int interestOps) {
        boolean read = (interestOps & SelectionKey.OP_READ) != 0;
        boolean write = (interestOps & SelectionKey.OP_WRITE) != 0;
        if (read) {
            if (write) {
                return ALL;
            } else {
                return READ;
            }
        } else if (write) {
            return WRITE;
        } else {
            return NONE;
        }
    }

    private final int interestOps;

    private final String name;

    private CommModeMask(int interestOps, String name) {
        this.interestOps = interestOps;
        this.name = name;
    }

    /**
     * Returns the name of this mask.
     */
    public String getName() {
        return name;
    }

    /**
     * Returns <tt>true</tt> if this mask allows a read operation.
     */
    public boolean isReadable() {
        return (interestOps & SelectionKey.OP_READ) != 0;
    }

    /**
     * Returns <tt>true</tt> if this mask allows a write operation.
     */
    public boolean isWritable() {
        return (interestOps & SelectionKey.OP_WRITE) != 0;
    }

    /**
     * Returns an interestOps of {@link SelectionKey} for this mask.
     */
    public int getInterestOps() {
        return interestOps;
    }

    /**
     * Peforms an <tt>AND</tt> operation on this mask with the specified
     * <tt>mask</tt> and returns the result.
     */
    public CommModeMask and(CommModeMask mask) {
        return getInstance(interestOps & mask.interestOps);
    }

    /**
     * Peforms an <tt>OR</tt> operation on this mask with the specified
     * <tt>mask</tt> and returns the result.
     */
    public CommModeMask or(CommModeMask mask) {
        return getInstance(interestOps | mask.interestOps);
    }

    /**
     * Returns a negated mask of this one.
     */
    public CommModeMask not() {
        return getInstance(~interestOps);
    }

    /**
     * Peforms an <tt>XOR</tt> operation on this mask with the specified
     * <tt>mask</tt> and returns the result.
     */
    public CommModeMask xor(CommModeMask mask) {
        return getInstance(interestOps ^ mask.interestOps);
    }

    public String toString() {
        return name;
    }
}

